package com.clhbolg.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.clhbolg.constant.RedisConstant;
import com.clhbolg.domain.Article;
import com.clhbolg.domain.Comment;
import com.clhbolg.mapper.*;
import com.clhbolg.model.dto.*;
import com.clhbolg.service.IUniqueViewService;
import com.clhbolg.service.IWebsiteConfigService;
import com.clhbolg.service.WebInfoService;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @Author cailinhu
 * @Description TODO
 * @Date 2023/3/7 15:21
 * @Version 1.0
 */
@Service
public class WebInfoServiceImpl implements WebInfoService {

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    ArticleMapper articleMapper;
    @Resource
    CategoryMapper categoryMapper;
    @Resource
    CommentMapper commentMapper;
    @Resource
    TagMapper tagMapper;
    @Resource
    TalkMapper talkMapper;
    @Autowired
    IWebsiteConfigService websiteConfigService;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    IUniqueViewService uniqueViewService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Override
    public AuroraHomeInfoDTO getWebInfoConfig() throws ExecutionException, InterruptedException {
        //1、获得文章数量
        CompletableFuture<Long> articleCountFuture = CompletableFuture.supplyAsync(() -> articleMapper.selectCount(Wrappers.lambdaQuery(Article.class).eq(Article::getIsDelete, Boolean.FALSE))
            ,threadPoolTaskExecutor );
        //2、获得分类总数量
        CompletableFuture<Long> asyncCategoryCount = CompletableFuture.supplyAsync(() -> categoryMapper.selectCount(null),threadPoolTaskExecutor);
        //3、获得标签总数量
        CompletableFuture<Long> asyncTagCount = CompletableFuture.supplyAsync(() -> {
            Long count = tagMapper.selectCount(null);
            return count;
        },threadPoolTaskExecutor);
        //4、获得说说条数
        CompletableFuture<Long> asyncTalkCount = CompletableFuture.supplyAsync(() -> {
            Long count = talkMapper.selectCount(null);
            return count;
        },threadPoolTaskExecutor);
        //5、总访问量
        CompletableFuture<Integer> asyncViewCount = CompletableFuture.supplyAsync(() -> {
            Object count =redisTemplate.opsForValue().get(RedisConstant.BLOG_VIEWS_COUNT);
            return Integer.parseInt(Optional.ofNullable(count).orElse(0).toString());
        },threadPoolTaskExecutor);
        //6、网站基本信息
        CompletableFuture<WebsiteConfigDTO> asyncWebsiteConfig = CompletableFuture.supplyAsync(()->websiteConfigService.getWebsiteConfig());
        CompletableFuture.allOf(articleCountFuture,asyncCategoryCount,asyncTagCount,asyncTagCount,asyncViewCount,asyncWebsiteConfig).get();
        AuroraHomeInfoDTO build = AuroraHomeInfoDTO.builder()
            .articleCount(articleCountFuture.get())
            .categoryCount(asyncCategoryCount.get())
            .tagCount(asyncTagCount.get())
            .talkCount(asyncTalkCount.get())
            .websiteConfigDTO(asyncWebsiteConfig.get())
            .viewCount(asyncViewCount.get()).build();

        return build;
    }

    @Override
    public WebAdminInfoDTO getWebAdminInfo() {
        //获得网站社交参数
        Object count = redisTemplate.opsForValue().get(RedisConstant.BLOG_VIEWS_COUNT);
        Integer viewsCount = Convert.toInt(count, 0);
        //查询留言数量
        Long messageCount = commentMapper.selectCount(Wrappers.lambdaQuery(Comment.class).eq(Comment::getType, 2));
        //用户数量
        Long userCount = sysUserMapper.selectCount(Wrappers.lambdaQuery(SysUser.class).ne(SysUser::getUserId, UserConstants.ADMIN_ID));
        //文章数量
        Long articleCount = articleMapper.selectCount(new LambdaQueryWrapper<Article>()
            .eq(Article::getIsDelete, Boolean.FALSE));
        //一周的访问趋势图
        List<UniqueViewDTO> uniqueView= uniqueViewService.listUniqueViews();
        //文章贡献趋势
        List<ArticleStatisticsDTO> articleStatisticsDTOs = articleMapper.listArticleStatistics();
        //分类统计信息
        List<CategoryDTO> categoryDTOs = categoryMapper.listCategories();
        //标签统计
        List<TagDTO> tagDTOs = Convert.toList(TagDTO.class, tagMapper.selectList());
        //文章浏览量排行
        Set<ZSetOperations.TypedTuple> set = redisTemplate.opsForZSet().reverseRangeWithScores(RedisConstant.ARTICLE_VIEWS_COUNT, 0, 4);
        Map<Object, Double> articleMap = set.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
        //构建识图对象
        WebAdminInfoDTO auroraAdminInfoDTO = WebAdminInfoDTO.builder()
            .articleStatisticsDTOs(articleStatisticsDTOs)
            .tagDTOs(tagDTOs)
            .viewsCount(viewsCount)
            .messageCount(messageCount)
            .userCount(userCount)
            .articleCount(articleCount)
            .categoryDTOs(categoryDTOs)
            .uniqueViewDTOs(uniqueView)
            .build();
        if (CollectionUtils.isNotEmpty(articleMap)) {
            List<ArticleRankDTO> articleRankDTOList = listArticleRank(articleMap);
            auroraAdminInfoDTO.setArticleRankDTOs(articleRankDTOList);
        }
        return auroraAdminInfoDTO;
    }

    /**
     * 封装文章基本信息
     *
     * @param articleMap
     * @return
     */
    private List<ArticleRankDTO> listArticleRank(Map<Object, Double> articleMap) {
        List<ArticleRankDTO> rank = new ArrayList<>();
        articleMap.forEach((k,v)->{
            Article article = articleMapper.selectById(Convert.toLong(k));
            ArticleRankDTO build = ArticleRankDTO.builder().articleTitle(article.getArticleTitle()).viewsCount(v.intValue()).build();
            rank.add(build);
        });
        List<ArticleRankDTO> collect = rank.stream().sorted(Comparator.comparingInt(ArticleRankDTO::getViewsCount).reversed()).collect(Collectors.toList());
        return collect;
    }
}
